// protocol 协议
#pragma once
#include "localcommon.hpp"
#include "localsocket.hpp"

#include <json/json.h>

// Request->计算机输入->序列化&反序列化
// Response->计算机输出->序列化&反序列化

// 约定好各个字段的含义，本质就是约定好协议！
// client -> server
// 如何要做序列化和反序列化：
// 1. 我们自己写(怎么做) ---> 往往不具备很好的扩展性
// 2. 使用现成的方案(这个是我们要写的) ---> json -> jsoncpp

const static std::string gl_MessHead = "\r\n";

class Request
{
public:
    /**********Request**************/
    Request() {}
    ~Request() {}
    /**********成员函数**************/
    std::string Serialize(const int x, const int y, const char oper)
    {
        Json::Value lo_self;
        lo_self["x"] = x;
        lo_self["y"] = y;
        lo_self["oper"] = oper;
        Json::FastWriter writer;
        std::string lo_message = writer.write(lo_self);
        return lo_message;
    }
    std::string Serialize()
    {
        Json::Value lo_self;
        lo_self["x"] = _x;
        lo_self["y"] = _y;
        lo_self["oper"] = _oper;
        Json::FastWriter writer;
        std::string lo_message = writer.write(lo_self);
        return lo_message;
    }
    bool Deserialize(const std::string &message)
    {
        Json::Value lo_self;
        Json::Reader lo_mess;
        bool ret_par = lo_mess.parse(message, lo_self);
        if (!ret_par)
        {
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "Deserialize error";
        }
        else
        {
            _x = lo_self["x"].asInt();
            _y = lo_self["y"].asInt();
            _oper = lo_self["oper"].asInt();
            std::cout << "-----Request---Deserialize------" << std::endl;
            std::cout << _x << std::endl;
            std::cout << _y << std::endl;
            std::cout << _oper << std::endl;
            std::cout << "---------------------------" << std::endl;
            Local_Log::LOG(Local_Log::LogLever::LDEBUG) << "Deserialize success";
        }
        return ret_par;
    }
    /**********Get**************/
    int Getx() { return _x; }
    int Gety() { return _y; }
    char Getoper() { return _oper; }
    /**********Set**************/
    void Setx(int x) { _x = x; }
    void Sety(int y) { _y = y; }
    void Setoper(char oper) { _oper = oper; }

    /**********Debug**************/
    void print()
    {
        std::cout << "x: " << _x
                  << "y: " << _y
                  << "oper: " << _oper
                  << std::endl;
    }

private:
    int _x;
    int _y;
    char _oper; // + - * / % -> _x _oper _y -> 10 + 20
};

class Response
{
public:
    /**********Response**************/
    Response() : _value(0), _code(0) {}
    ~Response() {}
    /**********成员函数**************/
    std::string Serialize(const int value, const int code)
    {
        Json::Value lo_self;
        lo_self["value"] = value;
        lo_self["code"] = code;
        Json::FastWriter writer;
        std::string lo_message = writer.write(lo_self);
        return lo_message;
    }
    std::string Serialize()
    {
        Json::Value lo_self;
        lo_self["value"] = _value;
        lo_self["code"] = _code;
        Json::FastWriter writer;
        std::string lo_message = writer.write(lo_self);
        return lo_message;
    }
    bool Deserialize(const std::string &message)
    {
        std::cout << "---------message---------" << std::endl;
        std::cout << message << std::endl;
        std::cout << "---------------------------" << std::endl;
        Json::Value lo_self;
        Json::Reader lo_mess;
        bool ret_par = lo_mess.parse(message, lo_self);
        if (!ret_par)
        {
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "Deserialize error";
        }
        else
        {
            _value = lo_self["value"].asInt();
            _code = lo_self["code"].asInt();
            Local_Log::LOG(Local_Log::LogLever::LDEBUG) << "Deserialize success";
        }
        return ret_par;
    }
    /**********Get**************/
    int Getvalue() { return _value; }
    int Getcode() { return _code; }
    /**********Set**************/
    void Setvalue(int value) { _value = value; }
    void Setcode(int code) { _code = code; }

    /**********Debug**************/
    void print()
    {
        std::cout << "value: " << _value
                  << "code: " << _code
                  << std::endl;
    }

private:
    int _value; // 运算结果，无法区分清楚应答是计算结果，还是异常值
    int _code;  // 0:sucess, 1,2,3,4->不同的运算异常的情况
};

using protask_t = std::function<Response(Request &req)>;

class Protocol
{
public:
    /**********Protocol**************/
    Protocol() {}
    Protocol(protask_t protask) : _protask(protask) {}
    ~Protocol() {}
    /**********成员函数**************/
    // 添加报头报尾
    std::string AddHead(const std::string &message)
    {
        std::string lo_size = std::to_string(message.size());
        std::string all_message = lo_size + gl_MessHead + message + gl_MessHead;
        return all_message;
    }
    // 获得删除报头报尾的报文
    bool Decode(std::string &message, std::string *buffer)
    {
        // 查找第一个gl_MessHead
        size_t ret_fin = message.find(gl_MessHead);
        if (ret_fin == std::string::npos)
        {
            std::cout << "------>" << ret_fin << std::endl;
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "Decode error not size";
            return false;
        }
        // 获得报文长度
        std::string lo_messlenstr = message.substr(0, ret_fin);
        int lo_messlen = std::stoi(lo_messlenstr);
        int lo_allsize = lo_messlenstr.size() + 2 * gl_MessHead.size() + lo_messlen;
        if (message.size() < lo_allsize)
        {
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "Decode error size short";
            return false;
        }
        // 获得报文
        *buffer = message.substr(ret_fin + gl_MessHead.size(), lo_messlen);
        // 移除报文
        message.erase(0, lo_allsize);
        return true;
    }
    // 解析报文
    void GetRequest(std::shared_ptr<Local_Sock_Mod::Socket> &sockfd, Local_Inetaddr::Inetaddr &client)
    {
        std::string lo_buffer;
        while (1)
        {
            // 1.读取报文
            int ret_rec = sockfd->Recv(&lo_buffer);
            if (ret_rec > 0)
            {
                std::cout << "---------lo_buffer---------" << std::endl;
                std::cout << lo_buffer << std::endl;
                std::cout << "---------------------------" << std::endl;
                // 2.判断报文完整性，不完整继续读
                std::string lo_message;
                while (Decode(lo_buffer, &lo_message))
                {
                    Local_Log::LOG(Local_Log::LogLever::LINFO) << "请求：" << lo_message;
                    std::cout << "---------lo_message---------" << std::endl;
                    std::cout << lo_message << std::endl;
                    std::cout << "---------------------------" << std::endl;
                    // 3.报文 反序列化
                    Request lo_req;
                    bool ret_des = lo_req.Deserialize(lo_message);
                    std::cout << "---------lo_req---------" << std::endl;
                    std::cout << lo_req.Getx() << std::endl;
                    std::cout << lo_req.Gety() << std::endl;
                    std::cout << lo_req.Getoper() << std::endl;
                    std::cout << "---------------------------" << std::endl;
                    if (!ret_des)
                        continue;
                    // 4.交付上层软件
                    Response lo_res = _protask(lo_req);
                    // 5.结果序列化
                    std::string lo_value = lo_res.Serialize();
                    std::cout << "---------lo_value---------" << std::endl;
                    std::cout << lo_value << std::endl;
                    std::cout << "---------------------------" << std::endl;
                    // 5.添加报头报尾
                    std::string lo_sendmess = AddHead(lo_value);
                    std::cout << "---------lo_sendmess---------" << std::endl;
                    std::cout << lo_sendmess << std::endl;
                    std::cout << "---------------------------" << std::endl;
                    // 6.写回网络
                    sockfd->Send(lo_sendmess);
                }
            }
            else if (ret_rec < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LINFO) << "read error";
                break;
            }
            else // if (ret_rec == 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LINFO) << "read end";
                break;
            }
        }
    }
    // 客户端 2.序列化 3.添加报头
    void BuildReques(std::unique_ptr<Local_Sock_Mod::Socket> &sockfd, Request &req)
    {
        std::string lo_mass = req.Serialize();
        std::cout << "---------lo_mass---------" << std::endl;
        std::cout << lo_mass << std::endl;
        std::cout << "---------------------------" << std::endl;
        std::string lo_allmass = AddHead(lo_mass);
        std::cout << "---------lo_allmass---------" << std::endl;
        std::cout << lo_allmass << std::endl;
        std::cout << "---------------------------" << std::endl;
        sockfd->Send(lo_allmass);
        // 发送失败判断未写
    }

    // 客户端 5.接收 6.反序列化
    void GetResponse(std::unique_ptr<Local_Sock_Mod::Socket> &sockfd, Response *res)
    {
        std::string lo_value;
        while (1)
        {
            int ret_rec = sockfd->Recv(&lo_value);
            std::cout << "---------lo_value---------" << std::endl;
            std::cout << lo_value << std::endl;
            std::cout << "---------------------------" << std::endl;
            std::string lo_buffer;
            if (ret_rec > 0)
            {
                while (Decode(lo_value, &lo_buffer))
                {
                    std::cout << "---------lo_buffer---------" << std::endl;
                    std::cout << lo_buffer << std::endl;
                    std::cout << "---------------------------" << std::endl;
                    // 6.反序列化
                    res->Deserialize(lo_buffer);
                    res->print();
                    return;
                }
                continue;
            }
            else if (ret_rec < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LINFO) << "read error";
                break;
            }
            else // if (ret_rec == 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LINFO) << "read end";
                break;
            }
        }
    }

    // 7.显示结果
    void ShowResponse(Response &res)
    {
        std::cout << "value: " << res.Getvalue() << " cord: " << res.Getcode() << std::endl;
    }

private:
    protask_t _protask;
};